home *** CD-ROM | disk | FTP | other *** search
- /* FSORT.C - sort a flat file using an array of indices to the strings. */
- extern unsigned int _stklen=15000;
- #define MAXITEMS 12
- #define BUFSIZE 1000
- #define MESSAGE 5
- #define READING "READING"
- #define WRITING "WRITING"
- #define SORTING "SORTING"
- #define NOTFLAT "\r\nRecords are not of identical length - exiting"
- #include <stdio.h>
- #include <conio.h>
- #include <alloc.h>
- #include <ctype.h>
- #include <dos.h>
- #include <stat.h>
- #include <io.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <string.h>
- typedef unsigned int SORTINFO;/* Hold line's array index only. */
- SORTINFO *position;/* Holds indices to file. */
- char *str1, *str2, *base; /* Pointer to base of array to be sorted. */
- long lbase, memleft=65000L;
-
- int clrline(int line);
- int compare(SORTINFO *s1, SORTINFO *s2);
- int copydata(char *buffer, int nitems, int lindex);
- int countconsec(int jj, int ii);
- int fileinfo(char *inname);
- void *getmem(void *ptr, long nbytes);
- int givecount(unsigned int count);
- int rcenter(char *str, int line);
-
- char *readbuf, *pbuf, *ptr, temp[BUFSIZE];
- int off[MAXITEMS], l[MAXITEMS];
- int order=1, nitems;
- unsigned long filesize, nrecs, elsize, pos;
- unsigned int recsize, nread, readsize, left;
- char line[300];
- char explain[]="\r\nUsage: FSORT <infile> <outfile> <order> <col1>...<coln>\r\n\n"
- " <infile> - file to sort (must be flat file)\r\n"
- " <outfile> - file to make\r\n"
- " <order> - A for Ascending, D for Descending\r\n"
- " <col1>...<coln> - column pairs to use\r\n\n"
- " For example: FSORT MYDATA.DTA MYSDATA.DTA A 1 5 25 30 22 26\r\n";
-
- /****************************/
- /* Clear the line selected. */
- /****************************/
- int clrline(int line)
- {
- gotoxy(1, line);
- clreol();
- return(0);
- }
- /**********************************/
- /* This compares the two strings. */
- /**********************************/
- int compare(SORTINFO *s1, SORTINFO *s2)
- {
- pos = lbase + (*s1)*elsize;
- str1 = (char *) (((pos/16)<<16) | pos%16);
- pos = lbase + (*s2)*elsize;
- str2 = (char *) (((pos/16)<<16) | pos%16);
- return (order*strncmp(str1, str2, elsize));
- }
- /***********************************************/
- /* This copies the data to the buffer to sort. */
- /***********************************************/
- int copydata(char *buffer, int nitems, int lindex)
- {
- register int i, j;
- if (buffer[recsize-1]!='\n'){
- clrscr();
- cprintf(NOTFLAT);
- exit(16);
- }
- pos = lbase + lindex*elsize;
- ptr = (char *) (((pos/16)<<16) | pos%16);
- for (j=i=0; i<nitems; j+=l[i], i++)
- strncpy(&ptr[j], &buffer[off[i]], l[i]);
- return 0;
- }
- /**************************************************************/
- /* This counts how many cosecutive records there are to read. */
- /**************************************************************/
- int countconsec(int jj, int ii)
- {
- register int i, j;
- int count;
- for (i=ii,j=jj,count=1; i<nrecs-1 && j<nread-1; i++, j++, count++)
- if (position[i+1] != position[i]+1) break;
- return (count);
- }
- /*********************************************************************/
- /* This determines the number of bytes per record of a fixed-record- */
- /* length file. */
- /*********************************************************************/
- int fileinfo(char *inname)
- {
- FILE *infile;
- char buffer[BUFSIZE];
- infile = fopen(inname, "rb");
- if (infile==NULL){
- cprintf("File %s not found\n", inname);
- exit(0);
- }
- fgets(buffer, BUFSIZE, infile);
- fclose(infile);
- return(strlen(buffer));
- }
- /**************************************************/
- /* Gets a chunk of memory to use for the sort. */
- /**************************************************/
- void *getmem(void *ptr, long nbytes)
- {
- ptr = farmalloc(nbytes);
- if (ptr == NULL) {
- clrline(MESSAGE);
- rcenter(" Out of memory", MESSAGE);
- exit(99);
- }
- return (ptr);
- }
- /*****************************************/
- /* This updates the count on the screen. */
- /*****************************************/
- int givecount(unsigned int count)
- {
- gotoxy(38, 12);
- cprintf("%d", count+1);
- return 0;
- }
- /********************************************************/
- /* Centers a string on the screen on the line selected. */
- /********************************************************/
- int rcenter(char *str, int line)
- {
- clrline(line);
- gotoxy(41-strlen(str)/2, line);
- return(cputs(str));
- }
- int main(int argc, char *argv[])
- {
- register unsigned int i, j;
- int inf, outf, count;
- if (argc<4) {
- cprintf(explain);
- exit(16);
- }
- recsize = fileinfo(argv[1]); /* Get record size. */
- outf = open(argv[2], O_CREAT|O_TRUNC|O_BINARY, S_IWRITE);
- inf = _open(argv[1], O_RDONLY|O_BINARY); /* Get size of file to sort. */
- filesize = filelength(inf);
- nrecs = filesize/recsize;
-
- if (toupper(argv[3][0])=='D') order = -1; /* Get sort order. */
- else if (toupper(argv[3][0])!='A') { /* Not legal - give message. */
- cprintf("\r\nUnknown sort order specified- not A or D\r\n");
- exit(99);
- }
- /* If no offset is specified, assume we use column 1. */
- nitems = argc - 4; /* Count number of items to pair. */
- nitems = nitems/2 + 1; /* Count number of pairs. */
-
- for (elsize=j=0, i=4; i<argc && i<nitems*2+4; i+=2, j++){
- off[j] = atoi(argv[i])-1;
- if (off[j] < 0){
- cprintf("\r\nColumn %s not valid\r\n", argv[i]);
- exit(99);
- }
- l[j] = (off[j+1] = atoi(argv[i+1])-1) - off[j] +1;
- if (l[j] < 0){
- cprintf("\r\nColumn %s cannot be smaller than the preceding column (%s).\r\n", argv[i+1], argv[i]);
- exit(99);
- }
- elsize += l[j];
- }
- if (!elsize || argc==4) { /* Assume sort on first 20 columns. */
- off[0] = nitems = 1;
- l[0] = elsize = 20;
- }
-
- /* Build table used to hold the string indexes. */
- position = (SORTINFO *) getmem((SORTINFO *) position, nrecs * sizeof(SORTINFO));
-
- /* Get memory for table to use for sorting. */
- base = getmem(base, nrecs * elsize);
- lbase = (unsigned long) FP_SEG(base);/* Convert pointer to a long. */
- lbase *= 16;
- lbase += FP_OFF(base);
- for (i=0; i<nrecs; i++) position[i] = i;
-
- memleft = min(65000L, farcoreleft());
- nread = (unsigned int) min(nrecs, memleft/ recsize);
- readsize = (unsigned) nread*recsize;
- pbuf = getmem(pbuf, readsize);/* Get temporary buffer for reading. */
-
- /* Read file in and build table of sortable data. */
- rcenter(READING, MESSAGE);
- for (i=0; i<nrecs; ){
- left = (unsigned) _read(inf, pbuf, readsize);
- for (j=0; j<left/recsize && i<nrecs; j++, i++){
- copydata(&pbuf[j*recsize], nitems, i);
- if (i%25 == 24) givecount(i);
- }
- }
- givecount(i);
- farfree(pbuf);
-
- /* Sort file, using qsort. */
- rcenter(SORTING, MESSAGE);
- qsort(&position[0], nrecs, sizeof(SORTINFO), compare);
-
- /* Write file back out. */
- clrline(12);
- pbuf = (char *) getmem((char *) pbuf, readsize);
- for (i=0; i<nrecs; ) {
- rcenter(WRITING, MESSAGE);
- /* Fill up buffer with records to write. */
- for (j=0; j<nread && i<nrecs; i+=count, j+=count){
- /* See if there are any consecutive records to read. */
- count = countconsec(i, j);
- lseek(inf, ((long) position[i]) * recsize, SEEK_SET);
- _read(inf, &pbuf[j*recsize], count*recsize);
- givecount(i+count);
- }
- givecount(i);
- write(outf, pbuf, j*recsize); /* Write out this piece. */
- }
- givecount(i);
- farfree(pbuf);
- farfree(base);
- farfree(position);
- close(outf);
- close(inf);
- exit(0);
- }